#ifndef Logger_INCLUDED
#define Logger_INCLUDED

#include "channel.h"
#include "loggerpriority.h"
#include "thread.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include <map>
#include <list>

using std::list;
using std::map;

// 一个 Logger 里，不能有多个相同的 Channel_Type 的 Channel
// 即不能有两个 FileChannel 或 ConsoleChannel
// 这时需要用多个 logger,
// 这样做是因为，暂时感觉没必要把一条信息写到多个文件中
//
class Logger: public Runnable
{
public:
    Logger(const string& name, const string& level = PriorityString[LOG_INFO]);
    ~Logger();
    
    const string& name();
    
    void addChannel(Channel* pChannel);
    void removeChannel(Channel* pChannel);
    
    void setLevel(const string& level);
    
    inline void log(LogPriority prio,const char* file,int line,const char* fmt, ...)
    {
        if ( prio < m_level)
            return;

        va_list args;
        va_start(args,fmt);
        int len = 256;
        char* pmsg = new char[len];
        memset(pmsg,0,len);
        int ret = vsnprintf(pmsg,len - 1,fmt,args);
        if (ret >= len)
        {
            delete [] pmsg;
            len = ret + 1;
            pmsg = new char[len];
            memset(pmsg,0,len);
            va_end(args);
            va_start(args,fmt);
            vsnprintf(pmsg,len,fmt,args);
        }
        va_end(args);
        
        int tid = syscall(SYS_gettid);

        LogMsg *plogmsg = new LogMsg(pmsg,prio,file,line,tid);
        // console 的单独打印
        if (m_console != NULL)
            m_console->log(*plogmsg);

        // 即便只有 console channel，添加后也会正常删除
        addMsg(plogmsg);
    }
    
protected:
    int parseLevel(const string& level);
    void addMsg(LogMsg* pmsg);
    virtual void run();
private:
    Logger();
    Logger(const Logger& other);
    Logger& operator = (const Logger& other);
    
    string              m_name;
    int                 m_level;

    bool                m_running;
    Mutex               m_msgMutex;
    Thread              m_thread;
    list<LogMsg*>       *m_writeQueue;
    list<LogMsg*>       *m_cacheQueue;
    
    // console channel 单独拿出来，
    // 有时候，日志还没打印，进程已经结束了，
    // 有 console channel 时，单独打印
    Channel*            m_console;
    // m_channels 保存其他类型的 channel
    map<Channel_Type,Channel*>     m_channels;
};


//
// inlines
//

inline const string& Logger::name()
{
    return m_name;
}

#define log_fatal(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_FATAL,__FILE__,__LINE__,fmt,##args)

#define log_error(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_ERROR,__FILE__,__LINE__,fmt,##args)

#define log_warning(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_WARNING,__FILE__,__LINE__,fmt,##args)

#define log_info(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_INFO,__FILE__,__LINE__,fmt,##args)

#define log_debug(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_DEBUG,__FILE__,__LINE__,fmt,##args)

#define log_trace(logger, fmt, args...) \
    if (logger != NULL) logger->log(LOG_TRACE,__FILE__,__LINE__,fmt,##args)

#endif









